#!/usr/bin/env nu
# Info: Script to run Provisioning Workspace Management
# Author: JesusPerezLorenzo
# Release: 1.0.0
# Date: 29-09-2025

use std log

use lib_provisioning *
use env.nu *

# - > Help on Workspace
export def "main help" [
  --src: string = ""
  --notitles       # not titles
  --out: string    # Print Output format: json, yaml, text (default)
]: nothing -> nothing {
  if $notitles == null or not $notitles { show_titles }
  ^$"($env.PROVISIONING_NAME)" -mod workspace --help
  if ($out | is-not-empty) { $env.PROVISIONING_NO_TERMINAL = false }
  print (provisioning_options $src)
  if not $env.PROVISIONING_DEBUG { end_run "" }
}

# > Workspace Management
def main [
  ...args: string  # Other options, use help to get info
  -v               # Show version
  -i               # Show Info
  --version (-V)   # Show version with title
  --info (-I)      # Show Info with title
  --about (-a)     # Show About
  --infra: string  # Infrastructure name
  --template: string = "minimal"  # Template type: minimal, full, example
  --workspace-type: string = "development"  # Workspace type
  --user-name: string = ""  # User name for workspace
  --taskservs: list<string> = []  # Taskservs to load during init
  --providers: list<string> = []  # Providers to load during init
  --clusters: list<string> = []   # Clusters to load during init
  --dep-option: string = ""        # Dependency option: home-package, git-package, publish-repo, workspace-home
  --dep-url: string = ""           # Dependency URL for git-package or publish-repo
  --overwrite      # Overwrite existing workspace
  --check (-c)     # Only check mode, no actual changes
  --yes (-y)       # Confirm task
  --debug (-x)     # Use Debug mode
  --xm             # Debug with PROVISIONING_METADATA
  --xld            # Log level with DEBUG PROVISIONING_LOG_LEVEL=debug
  --metadata       # Error with metadata (-xm)
  --notitles       # Do not show banner titles
  --helpinfo (-h)  # For more details use options "help" (no dashes)
  --out: string    # Print Output format: json, yaml, text (default)
]: nothing -> nothing {
  if ($out | is-not-empty) {
    $env.PROVISIONING_OUT = $out
    $env.PROVISIONING_NO_TERMINAL = true
  }
  provisioning_init $helpinfo "workspace" $args
  if $version or $v { ^$env.PROVISIONING_NAME -v ; exit }
  if $info or $i { ^$env.PROVISIONING_NAME -i ; exit }
  if $about {
    _print (get_about_info)
    exit
  }
  if $debug { $env.PROVISIONING_DEBUG = true }
  if $metadata { $env.PROVISIONING_METADATA = true }

  let task = if ($args | length) > 0 { ($args | get 0) } else { "" }
  let ops = if ($args | length) > 1 { ($args | skip 1 | str join " ") } else { "" }

  # Extract workspace path (first non-flag argument)
  let workspace_path = if ($ops | is-not-empty) and not ($ops | str starts-with "-") {
    let parts = ($ops | split row " ")
    let first_part = ($parts | get 0)
    # Stop at first flag
    if ($first_part | str starts-with "-") {
      "."
    } else {
      $first_part
    }
  } else {
    "."
  }

  $env.PROVISIONING_MODULE = "workspace"

  match $task {
    "h" | "help" => {
      # Redirect to main categorized help system
      exec $"($env.PROVISIONING_NAME)" help workspace --notitles
    },
    "init" => {
      if $overwrite and $check {
        workspace_init $workspace_path --infra $infra --template $template --workspace-type $workspace_type --user-name $user_name --taskservs $taskservs --providers $providers --clusters $clusters --dep-option $dep_option --dep-url $dep_url --overwrite --check
      } else if $overwrite {
        workspace_init $workspace_path --infra $infra --template $template --workspace-type $workspace_type --user-name $user_name --taskservs $taskservs --providers $providers --clusters $clusters --dep-option $dep_option --dep-url $dep_url --overwrite
      } else if $check {
        workspace_init $workspace_path --infra $infra --template $template --workspace-type $workspace_type --user-name $user_name --taskservs $taskservs --providers $providers --clusters $clusters --dep-option $dep_option --dep-url $dep_url --check
      } else {
        workspace_init $workspace_path --infra $infra --template $template --workspace-type $workspace_type --user-name $user_name --taskservs $taskservs --providers $providers --clusters $clusters --dep-option $dep_option --dep-url $dep_url
      }
    },
    "create" => {
      print $"📁 Creating workspace: ($workspace_path)"
      if $check {
        workspace_create $workspace_path --infra $infra --template $template --check
      } else {
        workspace_create $workspace_path --infra $infra --template $template
      }
    },
    "migrate" => {
      print $"🔄 Migrating workspace: ($workspace_path)"
      if $check {
        workspace_migrate $workspace_path --check
      } else {
        workspace_migrate $workspace_path
      }
    },
    "validate" => {
      let result = workspace_validate $workspace_path
      if $result.valid {
        print $"✅ Workspace is valid: ($workspace_path)"
      } else {
        print $"❌ Workspace validation failed: ($workspace_path)"
        print $"Missing directories: ($result.missing_directories)"
        print $"Missing files: ($result.missing_files)"
        print $"Recommendations: ($result.recommendations)"
      }
      if ($out | is-not-empty) {
        if $out == "json" {
          print ($result | to json)
        } else if $out == "yaml" {
          print ($result | to yaml)
        } else {
          print ($result | table)
        }
      }
    },
    "info" => {
      # Resolve path: explicit arg → active workspace → CWD
      let resolved_path = if $workspace_path != "." {
        $workspace_path
      } else {
        let ws_name = (get-active-workspace)
        if ($ws_name | is-not-empty) {
          let ws_path = (get-workspace-path $ws_name)
          if ($ws_path | is-not-empty) { $ws_path } else { "." }
        } else { "." }
      }
      let info = workspace_info $resolved_path
      print $"📊 Workspace Information:"
      print $"  Path: ($info.workspace)"
      print $"  Taskservs: ($info.taskservs_count) - ($info.taskservs | str join ', ')"
      print $"  Providers: ($info.providers_count) - ($info.providers | str join ', ')"
      print $"  Clusters: ($info.clusters_count) - ($info.clusters | str join ', ')"
      if ($out | is-not-empty) {
        if $out == "json" {
          print ($info | to json)
        } else if $out == "yaml" {
          print ($info | to yaml)
        } else {
          print ($info | table)
        }
      }
    },
    "status" => {
      let status = workspace_status $workspace_path
      print $"📈 Workspace Status:"
      print $"  Path: ($status.workspace)"
      print $"  Has new structure: ($status.has_new_structure)"
      print $"  Is migrated: ($status.is_migrated)"
      print $"  Backup files: ($status.backup_files)"
      if ($out | is-not-empty) {
        if $out == "json" {
          print ($status | to json)
        } else if $out == "yaml" {
          print ($status | to yaml)
        } else {
          print ($status | table)
        }
      }
    },
    "list" => {
      workspace_list --out $out
    },
    "rollback" => {
      if not $yes {
        print "⚠️  This will rollback the migration. Use --yes to confirm."
        exit 1
      }
      workspace_rollback $workspace_path
    },
    "dry-run" => {
      workspace_dry_run $workspace_path
    },
    "config" => {
      # Config subcommands
      let config_cmd = if ($ops | is-not-empty) {
        ($ops | split row " " | get 0)
      } else {
        "help"
      }
      let config_ops = $ops | str replace $config_cmd "" | str trim

      match $config_cmd {
        "show" => {
          let format_flag = if ($out | is-not-empty) { $out } else { "yaml" }
          let ws_name = if ($infra | is-not-empty) { $infra } else { "" }
          workspace-config-show $ws_name --format $format_flag
        },
        "validate" => {
          let ws_name = if ($infra | is-not-empty) { $infra } else { "" }
          workspace-config-validate $ws_name
        },
        "generate" => {
          let parts = ($config_ops | split row " ")
          if ($parts | length) < 2 {
            print "Usage: provisioning workspace config generate provider <name>"
            exit 1
          }
          let gen_type = ($parts | get 0)
          let gen_name = ($parts | get 1)
          if $gen_type == "provider" {
            let ws_name = if ($infra | is-not-empty) { $infra } else { "" }
            workspace-config-generate-provider $gen_name $ws_name
          } else {
            print $"Unknown generate type: ($gen_type)"
            exit 1
          }
        },
        "edit" => {
          let parts = ($config_ops | split row " ")
          if ($parts | length) < 1 {
            print "Usage: provisioning workspace config edit <type> [name]"
            print "Types: main, provider, platform, kms"
            exit 1
          }
          let edit_type = ($parts | get 0)
          let edit_name = if ($parts | length) > 1 { ($parts | get 1) } else { "" }
          let ws_name = if ($infra | is-not-empty) { $infra } else { "" }
          workspace-config-edit $edit_type $edit_name $ws_name
        },
        "hierarchy" => {
          let ws_name = if ($infra | is-not-empty) { $infra } else { "" }
          workspace-config-hierarchy $ws_name
        },
        "list" => {
          let ws_name = if ($infra | is-not-empty) { $infra } else { "" }
          let type_flag = if ($config_ops | is-not-empty) { $config_ops } else { "all" }
          workspace-config-list $ws_name --type $type_flag
        },
        "help" => {
          print "Workspace Configuration Commands:"
          print ""
          print "  config show [name] [--format yaml|json|toml]"
          print "    Show workspace configuration"
          print ""
          print "  config validate [name]"
          print "    Validate all workspace configs"
          print ""
          print "  config generate provider <name>"
          print "    Generate provider config from template"
          print ""
          print "  config edit <type> [name]"
          print "    Edit configuration file"
          print "    Types: main, provider, platform, kms"
          print ""
          print "  config hierarchy [name]"
          print "    Show configuration loading hierarchy"
          print ""
          print "  config list [name] [--type all|provider|platform|kms]"
          print "    List configuration files"
          print ""
          print "Use --infra <name> to specify workspace, or uses active workspace"
        },
        _ => {
          print $"Unknown config command: ($config_cmd)"
          print "Use 'provisioning workspace config help' for available commands"
          exit 1
        }
      }
    },
    _ => {
      print $"❌ Unknown task: ($task)"
      print "Use 'provisioning workspace help' for available commands"
      exit 1
    }
  }
}

# Initialize workspace
def workspace_init [
  path: string
  --infra: string
  --template: string
  --workspace-type: string
  --user-name: string
  --taskservs: list<string>
  --providers: list<string>
  --clusters: list<string>
  --dep-option: string
  --dep-url: string
  --overwrite
  --check
]: nothing -> nothing {
  # Validate workspace name - no hyphens allowed (causes KCL module resolution issues)
  let workspace_name = ($path | path basename)
  if ($workspace_name | str contains "-") {
    print $"❌ Error: Workspace name cannot contain hyphens: '($workspace_name)'"
    print ""
    print "   Hyphens in workspace names cause KCL module resolution issues."
    print $"   Use underscores instead: '($workspace_name | str replace -a '-' '_')'"
    print ""
    exit 1
  }

  # Validate infra name if provided - no hyphens allowed
  if ($infra | is-not-empty) and ($infra | str contains "-") {
    print $"❌ Error: Infrastructure name cannot contain hyphens: '($infra)'"
    print ""
    print "   Hyphens in infrastructure names cause KCL module resolution issues."
    print $"   Use underscores instead: '($infra | str replace -a '-' '_')'"
    print ""
    exit 1
  }

  let provisioning_root = $env.PROVISIONING? | default "/usr/local/provisioning"
  let init_script = ($provisioning_root | path join "tools" "workspace-init.nu")

  if not ($init_script | path exists) {
    print $"❌ Workspace init script not found: ($init_script)"
    exit 1
  }

  let infra_flag = if ($infra | is-not-empty) { ["--infra-name" $infra] } else { [] }
  let template_flag = if ($template | is-not-empty) { ["--template" $template] } else { [] }
  let workspace_type_flag = if ($workspace_type | is-not-empty) { ["--workspace-type" $workspace_type] } else { [] }
  let user_flag = if ($user_name | is-not-empty) { ["--user-name" $user_name] } else { [] }
  let dep_option_flag = if ($dep_option | is-not-empty) { ["--dep-option" $dep_option] } else { [] }
  let dep_url_flag = if ($dep_url | is-not-empty) { ["--dep-url" $dep_url] } else { [] }
  let overwrite_flag = if $overwrite { ["--overwrite"] } else { [] }
  let check_flag = if $check { ["--check"] } else { [] }

  let all_flags = ($infra_flag | append $template_flag | append $workspace_type_flag | append $user_flag | append $dep_option_flag | append $dep_url_flag | append $overwrite_flag | append $check_flag)

  if ($taskservs | is-empty) and ($providers | is-empty) and ($clusters | is-empty) {
    ^nu $init_script $path ...$all_flags
  } else {
    let taskservs_flag = if not ($taskservs | is-empty) { ["--taskservs" $taskservs] } else { [] }
    let providers_flag = if not ($providers | is-empty) { ["--providers" $providers] } else { [] }
    let clusters_flag = if not ($clusters | is-empty) { ["--clusters" $clusters] } else { [] }
    ^nu $init_script init $path ...$all_flags ...$taskservs_flag ...$providers_flag ...$clusters_flag
  }
}

# Create workspace structure
def workspace_create [
  path: string
  --infra: string
  --template: string
  --check
]: nothing -> nothing {
  if $check {
    workspace_init $path --infra $infra --template $template --check
  } else {
    workspace_init $path --infra $infra --template $template
  }
}

# Migrate workspace
def workspace_migrate [
  path: string
  --check
]: nothing -> nothing {
  let provisioning_root = $env.PROVISIONING? | default "/usr/local/provisioning"
  let migrate_script = ($provisioning_root | path join "tools" "workspace-migrate.nu")

  if not ($migrate_script | path exists) {
    print $"❌ Workspace migrate script not found: ($migrate_script)"
    exit 1
  }

  if $check {
    ^nu $migrate_script dry-run $path
  } else {
    ^nu $migrate_script $path
  }
}

# Validate workspace
def workspace_validate [path: string]: nothing -> record {
  let workspace_abs = ($path | path expand)

  let required_dirs = [".taskservs", ".providers", ".clusters", ".manifest"]
  let required_files = ["kcl.mod"]

  let missing_dirs = $required_dirs | where {|dir|
    not (($workspace_abs | path join $dir) | path exists)
  }

  let missing_files = $required_files | where {|file|
    not (($workspace_abs | path join $file) | path exists)
  }

  let is_valid = ($missing_dirs | is-empty) and ($missing_files | is-empty)

  {
    valid: $is_valid
    workspace: $workspace_abs
    missing_directories: $missing_dirs
    missing_files: $missing_files
    recommendations: (if not $is_valid {
      ["Run 'provisioning workspace init <path>' to create or fix workspace structure"]
    } else {
      []
    })
  }
}

# Show workspace info
def workspace_info [path: string]: nothing -> record {
  let workspace_abs = ($path | path expand)

  if not ($workspace_abs | path exists) {
    print $"❌ Workspace does not exist: ($workspace_abs)"
    exit 1
  }

  let taskservs_manifest_path = ($workspace_abs | path join ".manifest" | path join "taskservs.yaml")
  let taskservs_manifest = if ($taskservs_manifest_path | path exists) {
    open $taskservs_manifest_path
  } else {
    { loaded_taskservs: [] }
  }

  let providers_manifest_path = ($workspace_abs | path join ".manifest" | path join "providers.yaml")
  let providers_manifest = if ($providers_manifest_path | path exists) {
    open $providers_manifest_path
  } else {
    { loaded_providers: [] }
  }

  let clusters_manifest_path = ($workspace_abs | path join ".manifest" | path join "clusters.yaml")
  let clusters_manifest = if ($clusters_manifest_path | path exists) {
    open $clusters_manifest_path
  } else {
    { loaded_clusters: [] }
  }

  {
    workspace: $workspace_abs
    taskservs_count: ($taskservs_manifest.loaded_taskservs? | default [] | length)
    providers_count: ($providers_manifest.loaded_providers? | default [] | length)
    clusters_count: ($clusters_manifest.loaded_clusters? | default [] | length)
    taskservs: ($taskservs_manifest.loaded_taskservs? | default [] | get -o name | default [])
    providers: ($providers_manifest.loaded_providers? | default [] | get -o name | default [])
    clusters: ($clusters_manifest.loaded_clusters? | default [] | get -o name | default [])
  }
}

# Show workspace migration status
def workspace_status [path: string]: nothing -> record {
  let workspace_abs = ($path | path expand)

  let has_new_structure = [".taskservs", ".providers", ".clusters", ".manifest"] | all {|dir|
    ($workspace_abs | path join $dir) | path exists
  }

  let migration_info_path = ($workspace_abs | path join ".migration-info.yaml")
  let migration_info = if ($migration_info_path | path exists) {
    open $migration_info_path
  } else {
    null
  }

  let backup_pattern = ($workspace_abs | path join "**/*.bak")
  let backup_result = (do { glob $backup_pattern | length } | complete)
  let backup_files = if $backup_result.exit_code == 0 {
    $backup_result.stdout
  } else {
    0
  }

  {
    workspace: $workspace_abs
    has_new_structure: $has_new_structure
    migration_info: $migration_info
    backup_files: $backup_files
    is_migrated: ($has_new_structure and ($migration_info != null))
  }
}

# List available workspaces
def workspace_list [
    --out: string
]: nothing -> nothing {
  let workspace_root = $env.PWD
  let infra_path = ($workspace_root | path join "infra")

  # Check if we're in a workspace directory
  if not ($infra_path | path exists) {
    print $"📁 Current directory: ($workspace_root)"
    print "❌ Not in a workspace directory (no 'infra/' subdirectory found)"
    print ""
    print "To use this command:"
    print "  1. Navigate to a workspace directory: cd <workspace-path>"
    print "  2. Or create a new workspace: provisioning ws init <name>"
    print ""
    print "Example:"
    print "  provisioning ws init my-workspace"
    print "  cd my-workspace"
    print "  provisioning ws list"
    return
  }

  # Get list of infrastructure directories
  let infra_dirs = (ls $infra_path | where type == dir)

  if ($infra_dirs | is-empty) {
    print $"📁 Workspace: ($workspace_root)"
    print "⚠️  No infrastructure configurations found in infra/"
    print ""
    print "Create an infrastructure:"
    print "  provisioning ws init . --infra <name>"
    return
  }

  # Build infrastructure info
  let infra_info = ($infra_dirs | each {|dir|
    let infra_name = ($dir.name | path basename)
    let infra_full_path = $dir.name
    let has_servers = ($infra_full_path | path join "servers.k") | path exists
    let has_kcl_mod = ($infra_full_path | path join "kcl.mod") | path exists

    # Count loaded modules
    let taskservs_manifest = ($infra_full_path | path join ".manifest" "taskservs.yaml")
    let providers_manifest = ($infra_full_path | path join ".manifest" "providers.yaml")

    let taskservs_count = if ($taskservs_manifest | path exists) {
      let manifest = (open $taskservs_manifest)
      ($manifest | get -o loaded_taskservs | default [] | length)
    } else { 0 }

    let providers_count = if ($providers_manifest | path exists) {
      let manifest = (open $providers_manifest)
      ($manifest | get -o loaded_providers | default [] | length)
    } else { 0 }

    {
      name: $infra_name
      path: $infra_full_path
      servers_config: $has_servers
      kcl_mod: $has_kcl_mod
      taskservs: $taskservs_count
      providers: $providers_count
    }
  })

  # Output based on format
  if ($out | is-not-empty) {
    if $out == "json" {
      print ($infra_info | to json)
    } else if $out == "yaml" {
      print ($infra_info | to yaml)
    } else {
      print ($infra_info | table)
    }
  } else {
    # Pretty output
    print $"📁 Workspace: ($workspace_root)"
    print $"📂 Infrastructure configurations: ($infra_info | length)"
    print ""

    $infra_info | each {|infra|
      print $"  (_ansi green_bold)($infra.name)(_ansi reset)"
      print $"    Path: infra/($infra.name)"
      print $"    Servers config: ($infra.servers_config)"
      print $"    KCL module: ($infra.kcl_mod)"
      print $"    Taskservs loaded: ($infra.taskservs)"
      print $"    Providers loaded: ($infra.providers)"
      print ""
    }

    print "Usage:"
    print $"  cd infra/<name>           # Navigate to infrastructure"
    print $"  provisioning ws init . --infra <name>  # Add new infrastructure"
  }
}

# Rollback workspace migration
def workspace_rollback [path: string]: nothing -> nothing {
  let provisioning_root = $env.PROVISIONING? | default "/usr/local/provisioning"
  let migrate_script = ($provisioning_root | path join "tools" "workspace-migrate.nu")

  if not ($migrate_script | path exists) {
    print $"❌ Workspace migrate script not found: ($migrate_script)"
    exit 1
  }

  ^nu $migrate_script rollback $path
}

# Dry run migration
def workspace_dry_run [path: string]: nothing -> nothing {
  let provisioning_root = $env.PROVISIONING? | default "/usr/local/provisioning"
  let migrate_script = ($provisioning_root | path join "tools" "workspace-migrate.nu")

  if not ($migrate_script | path exists) {
    print $"❌ Workspace migrate script not found: ($migrate_script)"
    exit 1
  }

  ^nu $migrate_script dry-run $path
}
